package com.gl.glbooks.services;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.flex.messaging.MessageTemplate;
import org.springframework.flex.remoting.RemotingDestination;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.gl.glbooks.repository.GenericRepository;
import com.gl.glbooks.spring.aop.aspectj.cache.Descachea;
import com.gl.glbooks.vos.Actividad;
import com.gl.glbooks.vos.Categoria;
import com.gl.glbooks.vos.Comentario;
import com.gl.glbooks.vos.Confirmacion;
import com.gl.glbooks.vos.Constants;
import com.gl.glbooks.vos.Editorial;
import com.gl.glbooks.vos.Ejemplar;
import com.gl.glbooks.vos.EstadoEjemplar;
import com.gl.glbooks.vos.EstadoSugerencia;
import com.gl.glbooks.vos.EstadoSugerenciaPDFsubido;
import com.gl.glbooks.vos.Libro;
import com.gl.glbooks.vos.LibroDigital;
import com.gl.glbooks.vos.LibroFisico;
import com.gl.glbooks.vos.Oficina;
import com.gl.glbooks.vos.PalabraClave;
import com.gl.glbooks.vos.Sugerencia;
import com.gl.glbooks.vos.SugerenciaPDFsubido;
import com.gl.glbooks.vos.Usuario;

import flex.messaging.FlexContext;

public class AgregarServices implements IAgregarServices {

	protected final Log logger = LogFactory.getLog(getClass());
	@SuppressWarnings("rawtypes")
	@Autowired
	GenericRepository repo;
	@Autowired
	private IMailServices aServiceMail;
	@Autowired
	private IListarServices aListarService;
	@Autowired
	MessageTemplate defaultMessageTemplate;

	@SuppressWarnings("unchecked")
	@Descachea(cacheKey = "libros")
	public Confirmacion agregarEjemplar(Ejemplar ejemplar,
			LibroFisico libroFisico) {
		Confirmacion confirmacion = new Confirmacion();
		int numeroCopiaProximo = 0;

		numeroCopiaProximo = libroFisico.getEjemplar().size() + 1;

		ejemplar.setFechaIngreso(new Date());
		ejemplar.setNumeroCopia(numeroCopiaProximo);
		ejemplar.setEstadoEjemplar(EstadoEjemplar.disponible);
		ejemplar.setLibrofisico(libroFisico);
		libroFisico.addEjemplar(ejemplar);
		logger.info("saveEjemplar");
		repo.save(ejemplar);
		defaultMessageTemplate.send("actualizacion", Constants.ACTUALIZACION_LIBROS );
		confirmacion.setEstado(Constants.CONFIRMACION_OK);
		confirmacion.setErrorString(Constants.MENSAJE_ALTA_EJEMPLAR);
		return confirmacion;
	}

	@Transactional
	@Descachea(cacheKey = "libros")
	public Confirmacion agregarLibro(Libro libro, Ejemplar ejemplar1,
			byte[] imagenLibro, byte[] pdfLibro) {

		Confirmacion confirmacion = new Confirmacion();
		confirmacion.setEstado(Constants.CONFIRMACION_ERROR);
		libro.setFechaAlta(new Date());
		if (imagenLibro != null) {
			String imagenesPath = FlexContext.getServletContext().getRealPath(
					"imagenes");
			File fileImagenLibro = new File(imagenesPath, libro.getImagen());

			try {
				FileOutputStream fileOutputStream = new FileOutputStream(
						fileImagenLibro);
				fileOutputStream.write(imagenLibro);
				fileOutputStream.close();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
				// todo retornar false...
			} catch (IOException e) {
				// todo retornar false...
				e.printStackTrace();
			}
		}

		if (libro instanceof LibroFisico) {

			LibroFisico libroFisico = (LibroFisico) libro;
			if (repo.find(LibroFisico.class, "ISBN", libroFisico.getISBN()) == null) {
				logger.info("saveLibroFisico");

				ejemplar1.setLibrofisico(libroFisico);
				ejemplar1.setEstadoEjemplar(EstadoEjemplar.disponible);
				ejemplar1.setNumeroCopia(1);
				ejemplar1.setFechaIngreso(new Date());
				libroFisico.addEjemplar(ejemplar1);
				libroFisico = (LibroFisico) repo.save(libroFisico);
				defaultMessageTemplate.send("actualizacion", Constants.ACTUALIZACION_LIBROS );
				confirmacion.setEstado(Constants.CONFIRMACION_OK);
				aServiceMail.avisoAltaLibro(libroFisico,
						aListarService.listarUsuarios());
			} else {
				confirmacion.setErrorString(Constants.MENSAJE_ERROR_ALTA_LIBRO);
			}
		} else if (libro instanceof LibroDigital) {
			logger.info("saveLibroDigital");

			LibroDigital libroDigital = (LibroDigital) libro;

			if (pdfLibro != null) {
				String pdfsPath = FlexContext.getServletContext().getRealPath(
						"pdfs");
				File filePdfLibro = new File(pdfsPath, libroDigital.getUrl());

				try {
					FileOutputStream fileOutputStream = new FileOutputStream(
							filePdfLibro);
					fileOutputStream.write(pdfLibro);
					fileOutputStream.close();
				} catch (FileNotFoundException e) {
					e.printStackTrace();
					// todo retornar false...
				} catch (IOException e) {
					// todo retornar false...
					e.printStackTrace();
				}
				libroDigital = (LibroDigital) repo.save(libroDigital);
				confirmacion.setEstado(Constants.CONFIRMACION_OK); // OK
				defaultMessageTemplate.send("actualizacion", Constants.ACTUALIZACION_LIBROS );
				if (libroDigital.getEditorial().getNombre().equalsIgnoreCase("")
						&& libroDigital.getIdioma().equalsIgnoreCase("")) {
					aServiceMail.avisoAprobarLibro(aListarService.listarUsuariosResponsables());
				} else {
					aServiceMail.avisoAltaLibro(libroDigital,
							aListarService.listarUsuarios());
				}

			}
		}
		return confirmacion;
	}

	@Transactional
	@Descachea(cacheKey = "libros")
	public Confirmacion modificarLibro(Libro libro, byte[] imagenLibro) {

		Confirmacion confirmacion = new Confirmacion();
		confirmacion.setEstado(Constants.CONFIRMACION_ERROR);

		byte[] imagenAntes = null;
		Libro libroAnterior = new Libro();
		libroAnterior = (Libro) repo.find(Libro.class, libro.getId());

		ILibroServices ilibroservice = new LibroServices();
		// imagenAntes = ilibroservice.buscarImagenLibro(libroAnterior);

		if (imagenLibro != null) {
			String imagenesPath = FlexContext.getServletContext().getRealPath(
					"imagenes");

			// Se borra la anterior si la tiene
			if (libroAnterior.getImagen() != null
					&& !libroAnterior.getImagen().isEmpty()) {
				File fileImagenLibroAnterior = new File(imagenesPath,
						libroAnterior.getImagen());
				fileImagenLibroAnterior.delete();
			}

			// Se guarda la nueva imagen
			File fileImagenLibro = new File(imagenesPath, libro.getImagen());

			try {
				FileOutputStream fileOutputStream = new FileOutputStream(
						fileImagenLibro);
				fileOutputStream.write(imagenLibro);
				fileOutputStream.close();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		if (libro instanceof LibroFisico) {

			LibroFisico libroFisico = (LibroFisico) libro;

			logger.info("saveLibroFisico");
			repo.save(libroFisico);
			defaultMessageTemplate.send("actualizacion", Constants.ACTUALIZACION_LIBROS );
			confirmacion.setEstado(Constants.CONFIRMACION_OK);
		} else if (libro instanceof LibroDigital) {
			logger.info("saveLibroDigital");

			LibroDigital libroDigital = (LibroDigital) libro;
			repo.save(libroDigital);
			defaultMessageTemplate.send("actualizacion", Constants.ACTUALIZACION_LIBROS );
			confirmacion.setEstado(Constants.CONFIRMACION_OK);
		}
		return confirmacion;
	}

	@Transactional
	@Descachea(cacheKey = "libros")
	public Confirmacion agregarLibroSugeridoPdf(LibroDigital libroDigital,
			byte[] imagenLibro, SugerenciaPDFsubido sugerenciaPdfsubido) {

		Confirmacion confirmacion = new Confirmacion();
		LibroDigital libroAnterior = new LibroDigital();

		libroAnterior = (LibroDigital) repo.find(Libro.class,
				libroDigital.getId());
		confirmacion.setEstado(Constants.CONFIRMACION_ERROR);

		if (imagenLibro != null) {
			String imagenesPath = FlexContext.getServletContext().getRealPath(
					"imagenes");

			// Se borra la anterior si la tiene
			if (libroAnterior.getImagen() != null
					&& !libroAnterior.getImagen().isEmpty()) {
				File fileImagenLibroAnterior = new File(imagenesPath,
						libroAnterior.getImagen());
				fileImagenLibroAnterior.delete();
			}

			// Se guarda la nueva imagen
			File fileImagenLibro = new File(imagenesPath,
					libroDigital.getImagen());

			try {
				FileOutputStream fileOutputStream = new FileOutputStream(
						fileImagenLibro);
				fileOutputStream.write(imagenLibro);
				fileOutputStream.close();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		// TODO: Gustavo 17-5 Que pasa si no lo graba y da error?
		logger.info("saveLibroDigital");

		sugerenciaPdfsubido
				.setEstadoSugerenciaPDFsubido(EstadoSugerenciaPDFsubido.aprobada);
		repo.save(libroDigital);
		repo.save(sugerenciaPdfsubido);
		confirmacion.setEstado(Constants.CONFIRMACION_OK);

		return confirmacion;
	}

	@Transactional
	public Confirmacion agregarLibroPdfsinAprobar(
			SugerenciaPDFsubido libroDigital, byte[] imagenLibro,
			byte[] pdfLibro) {

		logger.info("saveLibroDigitalSubido");
		Confirmacion confirmacion = new Confirmacion();
		confirmacion.setEstado(Constants.CONFIRMACION_ERROR);
		libroDigital
				.setEstadoSugerenciaPDFsubido(EstadoSugerenciaPDFsubido.sinRevisar);
		if (imagenLibro != null) {
			String imagenesPath = FlexContext.getServletContext().getRealPath(
					"imagenes");
			File fileImagenLibro = new File(imagenesPath,
					libroDigital.getImagen());

			try {
				FileOutputStream fileOutputStream = new FileOutputStream(
						fileImagenLibro);
				fileOutputStream.write(imagenLibro);
				fileOutputStream.close();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
				// todo retornar false...
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		if (pdfLibro != null) {
			String pdfsPath = FlexContext.getServletContext().getRealPath(
					"pdfs");
			File filePdfLibro = new File(pdfsPath, libroDigital.getUrl());

			try {
				FileOutputStream fileOutputStream = new FileOutputStream(
						filePdfLibro);
				fileOutputStream.write(pdfLibro);
				fileOutputStream.close();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
				// todo retornar false...
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			// libroDigital.setEstadoSugerenciaPDFsubido(EstadoSugerenciaPDFsubido.sinRevisar);
			repo.save(libroDigital);
			confirmacion.setEstado(Constants.CONFIRMACION_OK); // OK
			aServiceMail.avisoAprobarLibro(aListarService
					.listarUsuariosResponsables());
		}
		// confirmacion.setEstado(Constants.CONFIRMACION_OK);
		return confirmacion;
	}

	@Transactional
	@Descachea(cacheKey = "categorias")
	public Confirmacion agregarCategoria(Categoria categoria) {
		Confirmacion confirmacion = new Confirmacion();

		if (repo.find(Categoria.class, "nombre", categoria.getNombre()) == null) {
			repo.save(categoria);
			confirmacion.setEstado(Constants.CONFIRMACION_OK);
			defaultMessageTemplate.send("actualizacion", Constants.ACTUALIZACION_CATEGORIAS );
			return confirmacion;
		} else {
			confirmacion.setEstado(Constants.CONFIRMACION_ERROR);
			confirmacion.setErrorString(Constants.MENSAJE_ERROR_ALTA_CATEGORIA);
			return confirmacion;
		}
	}

	@Transactional
	@Descachea(cacheKey = "editoriales")
	public Confirmacion agregarEditorial(Editorial editorial) {
		Confirmacion confirmacion = new Confirmacion();

		if (repo.find(Editorial.class, "nombre", editorial.getNombre()) == null) {
			repo.save(editorial);
			confirmacion.setEstado(Constants.CONFIRMACION_OK);
			defaultMessageTemplate.send("actualizacion", Constants.ACTUALIZACION_EDITORIALES );
			return confirmacion;
		} else {
			confirmacion.setEstado(Constants.CONFIRMACION_ERROR);
			confirmacion.setErrorString(Constants.MENSAJE_ERROR_ALTA_EDITORIAL);
			return confirmacion;
		}
	}

	@Transactional
	@Descachea(cacheKey = "oficinas")
	public Confirmacion agregarOficina(Oficina oficina) {
		Confirmacion confirmacion = new Confirmacion();

		if (repo.find(Oficina.class, "nombre", oficina.getNombre()) == null) {
			repo.save(oficina);
			confirmacion.setEstado(Constants.CONFIRMACION_OK);
			defaultMessageTemplate.send("actualizacion", Constants.ACTUALIZACION_OFICINAS );
			return confirmacion;
		} else {
			confirmacion.setEstado(Constants.CONFIRMACION_ERROR);
			confirmacion.setErrorString(Constants.MENSAJE_ERROR_ALTA_OFICINA);
			return confirmacion;
		}
	}
	
	@Transactional
	@Descachea(cacheKey = "palabrasClaves")
	public Confirmacion agregarPalabra(PalabraClave palabrasClaves) {
		Confirmacion confirmacion = new Confirmacion();

		if (repo.find(PalabraClave.class, "palabra",
				palabrasClaves.getPalabra()) == null) {
			repo.save(palabrasClaves);
			confirmacion.setEstado(Constants.CONFIRMACION_OK);
			defaultMessageTemplate.send("actualizacion", Constants.ACTUALIZACION_PALABRASCLAVES );
			return confirmacion;
		} else {
			confirmacion.setEstado(Constants.CONFIRMACION_ERROR);
			confirmacion.setErrorString(Constants.MENSAJE_ERROR_PALABRA_CLAVE);
			return confirmacion;
		}
	}

	@Transactional
	public Confirmacion agregarSugerencia(Sugerencia sugerencia) {
		Confirmacion confirmacion = new Confirmacion();
		sugerencia.setEstadoSugerencia(EstadoSugerencia.sinRevisar);

		sugerencia=(Sugerencia)repo.save(sugerencia);
		aServiceMail.sugerenciaCompra(aListarService.listarUsuariosResponsables(),sugerencia);
		defaultMessageTemplate.send("actualizacion", Constants.ACTUALIZACION_SUGERENCIAS );

		confirmacion.setEstado(Constants.CONFIRMACION_OK);
		confirmacion.setTipo( Constants.CONFIRMACION_ALTA_SUGERENCIA );
		confirmacion.setErrorString(Constants.MENSAJE_ALTA_SUGERENCIA);
		return confirmacion;
	}

	@Transactional
	public Confirmacion agregarActividad(Actividad actividad) {
		Confirmacion confirmacion = new Confirmacion();
		Usuario usuarioBuscado = null;
		usuarioBuscado = (Usuario) repo.find(Usuario.class, "nombreUsuario",
				actividad.getUsuario().getNombreUsuario());
		actividad.setUsuario(usuarioBuscado);
		repo.save(actividad);
		confirmacion.setEstado(Constants.CONFIRMACION_OK);
		defaultMessageTemplate.send("actualizacion", Constants.ACTUALIZACION_ACTIVIDADES );
		return confirmacion;
	}

	@Transactional
	public Confirmacion agregarComentarioLibro(Libro libro,
			Comentario comentario) {
		Confirmacion confirmacion = new Confirmacion();
		Usuario usuarioBuscado=null;
		usuarioBuscado = (Usuario) repo.find(Usuario.class, "nombreUsuario", comentario.getUsuario().getNombreUsuario());
		comentario.setUsuario(usuarioBuscado);
		libro.addComentario(comentario);
		comentario.setComentariolibro(libro);
		logger.info("saveComentarioLibro");

		confirmacion.setEstado(Constants.CONFIRMACION_OK);
		confirmacion.setTipo(Constants.CONFIRMACION_ALTA_COMENTARIO);
		confirmacion.setErrorString(Constants.MENSAJE_ALTA_COMENTARIO);

		repo.save(libro);
		defaultMessageTemplate.send("actualizacion", Constants.ACTUALIZACION_LIBROS );
		
		return confirmacion;
	}

	@Transactional
	public Oficina addOficinaAndReturn(Oficina oficina) {
		
		this.agregarOficina(oficina);
		Oficina oficinaBuscada=(Oficina)repo.find(Oficina.class, "nombre", oficina.getNombre());
		return oficinaBuscada;
	}
	
	@Transactional
	public Categoria addCategoriaAndReturn(Categoria categoria) {
		
		this.agregarCategoria(categoria);
		Categoria categoriaBuscada=(Categoria)repo.find(Categoria.class, "nombre", categoria.getNombre());
		return categoriaBuscada;
	}
	@Transactional
	public Editorial addEditorialAndReturn(Editorial editorial){
		
		this.agregarEditorial(editorial);
		Editorial editorialBuscada=(Editorial)repo.find(Editorial.class, "nombre", editorial.getNombre());
		return editorialBuscada;
	}
	
	@Transactional
	public LibroFisico addLibroFisicoAndReturn(LibroFisico libroFisico,Ejemplar ejemplar){
		
		this.agregarLibro(libroFisico, ejemplar, null, null);
		LibroFisico libroFisicoBuscado=(LibroFisico) repo.find(LibroFisico.class, "ISBN", libroFisico.getISBN());
		return libroFisicoBuscado;
	}
	
	
}
